package alg;

import entities.*;
import java.util.ArrayList;
import java.util.List;
import operators.QueryExecutionPlan;
import static alg.Constants.*;

/**
 *
 * @author Dragan Sahpaski
 */
public class Maintenance {

    public static double getMaintenanceCost(Domain domain, Table view, Table parent) {
        List<Atribute> matAtributes = new ArrayList<Atribute>();
        double tupleSize = 0;
        for (Atribute a : view.getMaterializedAtributes()) {
            matAtributes.add(a);
            tupleSize += a.getSizeInBytes();
        }
        Query query = new Query(domain, new ArrayList<Condition>(), matAtributes);
        QueryExecutionPlan plan = new QueryExecutionPlan(domain, query, (ViewGene) parent);
        plan.executePlan();
        double maintCost = plan.getDiskCost();

        double pageSizeBytes = domain.getSystemMetaData().getDiskPageSizeInBytes();
        double t = ((double) (view.getNumberOfTuples() * tupleSize)) / pageSizeBytes;

        for (Atribute a : view.getIndexedAtributes()) {
            maintCost += t + ((double) (a.getNumberOfDistinctValues() * view.getNumberOfTuples())) / (double) (8 * pageSizeBytes);
        }
        return maintCost;
    }

    public static double evaluateMaintenanceTimeOneView(Domain domain, Table view) {
        double minMaintCost = MAX_VALUE;
        for (Table parent : view.getAllParents()) {
            if (parent.isTableMaterialized()) {
                double maintCost = getMaintenanceCost(domain, view, (ViewGene) parent);
                if (maintCost < minMaintCost) {
                    minMaintCost = maintCost;
                }
            }
        }
        try {
            if (minMaintCost == MAX_VALUE && view.isRootView()) {
                minMaintCost = 0.0;
            }
            if (minMaintCost == MAX_VALUE) {
                throw new Exception("Invalid state must have a materialized parent view. The root view is always materialized.");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return minMaintCost;
    }

    public static double evaluateMaintanceTime(Domain domain) {
        double maintenanceCost = 0.0;
        for (Table view : domain.getMaterializedViews().values()) {
            maintenanceCost += evaluateMaintenanceTimeOneView(domain, view);
        }
        return maintenanceCost;
    }

    public static double evaluateDerivation(Domain d1, Domain d2) {
        double totalDeriveCost = 0.0;
        for (Integer index : d2.getMaterializedViews().keySet()) {
            if (d1.getMaterializedViews().containsKey(index)) {
                // Mora da se evaluiraat denorm atributi
                Table newView = d2.getMaterializedViews().get(index);
                Table oldView = d1.getMaterializedViews().get(index);
                List<Atribute> groupBy = new ArrayList<Atribute>();

                double tupleSize = 0;
                for (Atribute a : newView.getMaterializedAtributes()) {
                    if (!oldView.isAtributeMaterialized(a.getName())) {
                        groupBy.add(a);
                    }
                    tupleSize += a.getSizeInBytes();
                }
                Query query = new Query(d2, new ArrayList<Condition>(), groupBy);
                QueryExecutionPlan plan = new QueryExecutionPlan(d2, query, (ViewGene) newView);
                plan.executePlan();
                totalDeriveCost += plan.getDiskCost();

                double pageSizeBytes = d2.getSystemMetaData().getDiskPageSizeInBytes();
                double t = ((double) (newView.getNumberOfTuples() * tupleSize)) / pageSizeBytes;

                for (Atribute a : newView.getIndexedAtributes()) {
                    if (!oldView.isAtributeIndexed(a.getName())) {
                        totalDeriveCost += t + ((double) (a.getNumberOfDistinctValues() * newView.getNumberOfTuples())) / (double) (8 * pageSizeBytes);
                    }
                }
            } else {
                // Mora da se presmeta od pocetok
                Table view = d2.getMaterializedViews().get(index);
                totalDeriveCost += evaluateMaintenanceTimeOneView(d2, view);
            }
        }
        return totalDeriveCost;
    }
}






